package st.strategy.vo;

import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import org.apache.commons.math3.stat.descriptive.SynchronizedDescriptiveStatistics;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import st.BasicStockData;
import st.base.Sysdate;
import st.test.PreTest;
import st.test.TestDataInfo;

/**
 * 未成熟隨機值RSV＝(C－9L)／(9H－9L)×100 <br/>
 * 當日K值＝2／3×前一日K值＋1／3×當日RSV <br/>
 * 當日D值＝2／3×前一日D值＋1／3×當日K值
 */
public class Kd implements TechLine {
	public static void main(String[] args) {
		try {
			PreTest pt = new PreTest();
			TestDataInfo loadDataResult = pt.loadData(args);
			Kd kd = new Kd(loadDataResult.getStock(),
					loadDataResult.getStockDatas(), 9);
			kd.buildKd();
			int size = kd.kdData.size();
			size=size/2;
			System.out.println(kd.kdData.get(Sysdate.getInstance("20090602")));
			
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	protected int n;
	protected Collection<BasicStockData> stockDatas;
	protected SynchronizedDescriptiveStatistics rsvLDs;
	protected SynchronizedDescriptiveStatistics rsvHDs;
	protected Map<Sysdate, Double> KData;
	protected Map<Sysdate, Double> DData;
	protected Map<Sysdate, Double> rsvData;
	protected Map<Sysdate, KdValue> kdData;
	protected Stock stock;

	public Kd(Stock stock, Collection<BasicStockData> stockDatas, int n) {
		this.stockDatas = stockDatas;
		this.stock = stock;
		this.n = n;
		this.rsvLDs = new SynchronizedDescriptiveStatistics(this.n);
		this.rsvHDs = new SynchronizedDescriptiveStatistics(this.n);
		this.rsvData = new HashMap<Sysdate, Double>();
		this.KData = new HashMap<Sysdate, Double>();
		this.DData = new HashMap<Sysdate, Double>();
		this.kdData=new HashMap<Sysdate, KdValue>();
	}

	public void buildKd() {
		buildRsv();
		buildK();
		buildD();
		Set<Sysdate> dKeys = DData.keySet();
		for (Sysdate sysdate : dKeys) {
			KdValue value=new KdValue();
			Double k = KData.get(sysdate);
			Double d =DData.get(sysdate);
			Double rsv =rsvData.get(sysdate);
			value.setdValue(d);
			value.setkValue(k);
			value.setRsv(rsv);
			kdData.put(sysdate, value);
		}
	}

	Logger logger = LoggerFactory.getLogger(getClass());

	private void buildK() {
		double lastK;
		for (BasicStockData stockData : stockDatas) {
			Sysdate tradeDate = stockData.getTradeDate();
			Sysdate _lastTradeDate = tradeDate.add(-1, stock);
			Double _lastK;
			if (_lastTradeDate == null) {
				lastK = 50d;
			} else {
				_lastK = KData.get(_lastTradeDate);
				if (_lastK == null) {
					lastK = 50d;
				} else {
					lastK = _lastK.doubleValue();
				}
			}
			double rsv = rsvData.get(tradeDate);
			double k = lastK * (2d / 3d) + rsv * (1d / 3d);
			KData.put(tradeDate, k);
		}
	}

	private void buildD() {
		double lastD;
		for (BasicStockData stockData : stockDatas) {
			Sysdate tradeDate = stockData.getTradeDate();
			Sysdate _lastTradeDate = tradeDate.add(-1, stock);
			Double _lastD = DData.get(_lastTradeDate);
			if (_lastD == null) {
				lastD = 50d;
			} else {
				lastD = _lastD.doubleValue();
			}
			double k = KData.get(tradeDate);
			double d = ((lastD * (2d / 3d)) + (k * (1d / 3d)));
			DData.put(tradeDate, d);
		}
	}

	private void buildRsv() {
		for (BasicStockData stockData : stockDatas) {
			rsvLDs.addValue(stockData.getLowest());
			rsvHDs.addValue(stockData.getHighest());
			Sysdate _tradeDate = stockData.getTradeDate();
			double min = rsvLDs.getMin();
			double max = rsvHDs.getMax();
			double d = max - min;
			double rsv = (d == 0 ? 0
					: (((stockData.getClose() - min) / d) * 100d));
			rsvData.put(_tradeDate, rsv);
		}
	}

	@Override
	public KdValue getValue(Sysdate date) {
		return this.kdData.get(date);
	}
}
